/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.repair.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springblade.common.cache.CacheNames;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.repair.dto.sign.SignDetailSearchDTO;
import org.springblade.modules.repair.entity.MaintainSignCalendar;
import org.springblade.modules.repair.entity.MaintainSignSeting;
import org.springblade.modules.repair.entity.UserSignDetail;
import org.springblade.modules.repair.enums.SignTypeEnum;
import org.springblade.modules.repair.mapper.UserSignDetailMapper;
import org.springblade.modules.repair.service.IMaintainSignSetingService;
import org.springblade.modules.repair.service.IUserSignDetailService;
import org.springblade.modules.repair.utils.DateUtils;
import org.springblade.modules.repair.vo.HomeUserSignCountVO;
import org.springblade.modules.repair.vo.UserSignDetailVO;
import org.springblade.modules.repair.vo.plan.SignRangeVo;
import org.springblade.modules.repair.vo.sign.*;
import org.springblade.modules.system.service.IDeptService;
import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.system.vo.DeptTreeNode;
import org.springblade.modules.system.vo.DeptVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户签到明细表 服务实现类
 *
 * @author zcc
 * @since 2021-07-28
 */
@Service
public class UserSignDetailServiceImpl extends BaseServiceImpl<UserSignDetailMapper, UserSignDetail> implements IUserSignDetailService {


	@Autowired
	private IMaintainSignSetingService maintainSignSetingService;

	@Autowired
	private IUserService userService;

	@Autowired
	private IDeptService deptService;

	@Autowired
	private BladeRedis bladeRedis;

	@Override
	public IPage<UserSignDetailVO> selectUserSignDetailPage(IPage<UserSignDetailVO> page, UserSignDetailVO userSignDetail) {
		return page.setRecords(baseMapper.selectUserSignDetailPage(page, userSignDetail));
	}

	@Override
	public List<SignRangeVo> getSignRangeVoList(Long userId) {
		return baseMapper.getSignRangeVoList(AuthUtil.getTenantId(), userId);
	}

	@Override
	public List<UserSignDetail> list(Long userId, Integer beginDate, Integer endDate) {
		List<UserSignDetail> details = baseMapper.list(userId, beginDate, endDate);
		//表示值班
		Integer holiday = 2;
		for (UserSignDetail userSignDetail : details) {
			if (userSignDetail.getOrkforceId() != null) {
				userSignDetail.setHoliday(holiday);
			}
			userSignDetail.setOrkforceId(null);
		}
		return details.stream().distinct().collect(Collectors.toList());
	}

	@Override
	public MaintainSignCalendar getOne(Long userId, Integer today) {
		return baseMapper.getOne(userId, today);
	}

	@Override
	public UserSignDetailVo getUserSignDetail(SignDetailSearchDTO signDetailSearchDTO) {
		//考勤魔法值不再定义，具体参考数据库字段意思和model对象说明
		if (signDetailSearchDTO.getEndDate().getTime() > new Date().getTime()) {
			signDetailSearchDTO.setEndDate(new Date());
		}

		final List<MaintainSignSeting> list = maintainSignSetingService.list();
		final Map<Long, List<MaintainSignSeting>> map = list.stream().collect(Collectors.groupingBy(MaintainSignSeting::getId));

		UserSignDetailVo userSignDetailVo = new UserSignDetailVo();
		if (signDetailSearchDTO.getUserId() == null) {
			signDetailSearchDTO.setUserId(AuthUtil.getUserId());
		}

		List<UserSignDetail> details = baseMapper.list(signDetailSearchDTO.getUserId(), Convert.toInt(DateUtil.format(signDetailSearchDTO.getBeginDate(), "yyyyMMdd")), Convert.toInt(DateUtil.format(signDetailSearchDTO.getEndDate(), "yyyyMMdd")));

		//迟到的信息
		List<UserSignDetail> beLateCount = details.stream().filter(o -> o.getHoliday() == 0 && Convert.toInt(o.getSignBeLate(), -1) == 0).collect(Collectors.toList());
		userSignDetailVo.setBeLateCount(Convert.toInt(beLateCount.size(), 0));
		Integer beLateMinute = userSignDetailVo.getBeLateMinute();
		List<UserSignAbnormalVo> beLateDetails = new ArrayList<>(16);
		for (UserSignDetail userSignDetail : beLateCount) {
			UserSignAbnormalVo userSignAbnormalVo = new UserSignAbnormalVo();
			final Date date = userSignDetail.getBeSignDate();

			final MaintainSignSeting maintainSignSeting = map.get(userSignDetail.getSignSettingId()).get(0);
			String signDate1 = maintainSignSeting.getSignDate();
			final String signDate = DateUtil.format(date, "yyyy-MM-dd") + " " + signDate1;
			final DateTime dateTime = DateUtil.parse(signDate, "yyyy-MM-dd HH:mm");
			final Integer minute = Convert.toInt(DateUtil.between(dateTime, new Date(userSignDetail.getSignTime()), DateUnit.MINUTE));
			userSignAbnormalVo.setDate(DateUtil.format(date, "yyyy/MM/dd"));
			if (minute >= DateUtils.HOURS_MINUTE) {
				userSignAbnormalVo.setMsg("迟到" + DateUtils.minuteToHours(minute));
			} else {
				userSignAbnormalVo.setMsg("迟到" + minute + "分钟");
			}

			beLateMinute = beLateMinute + minute;
			beLateDetails.add(userSignAbnormalVo);
		}
		userSignDetailVo.setBeLateMinute(beLateMinute);
		if (beLateDetails.size() > 0) {
			userSignDetailVo.setBeLateDetails(beLateDetails);
		}

		//早退
		List<UserSignDetail> leaveEarlyCount = details.stream().filter(o -> o.getHoliday() == 0 && Convert.toInt(o.getSignOutLeaveEarly(), -1) == 0).collect(Collectors.toList());
		userSignDetailVo.setLeaveEarlyCount(leaveEarlyCount.size());
		List<UserSignAbnormalVo> leaveEarlyDetails = new ArrayList<>();
		Integer leaveEarlyMinute = userSignDetailVo.getLeaveEarlyMinute();
		for (UserSignDetail userSignDetail : leaveEarlyCount) {
			UserSignAbnormalVo userSignAbnormalVo = new UserSignAbnormalVo();
			final Date date = userSignDetail.getBeSignDate();

			final MaintainSignSeting maintainSignSeting = map.get(userSignDetail.getSignSettingId()).get(0);
			final String signDate = DateUtil.format(date, "yyyy-MM-dd") + " " + maintainSignSeting.getSignOutDate();
			final DateTime dateTime = DateUtil.parse(signDate, "yyyy-MM-dd HH:mm");
			Integer minute = Convert.toInt(DateUtil.between(dateTime, new Date(userSignDetail.getSignOutTime()), DateUnit.MINUTE));
			userSignAbnormalVo.setDate(DateUtil.format(date, "yyyy/MM/dd"));
			if (minute >= DateUtils.HOURS_MINUTE) {
				userSignAbnormalVo.setMsg("早退" + DateUtils.minuteToHours(minute));
			} else {
				minute = minute + 1;
				userSignAbnormalVo.setMsg("早退" + minute + "分钟");
			}

			leaveEarlyMinute = leaveEarlyMinute + minute;
			leaveEarlyDetails.add(userSignAbnormalVo);
		}
		userSignDetailVo.setLeaveEarlyMinute(leaveEarlyMinute);
		if (leaveEarlyDetails.size() > 0) {
			userSignDetailVo.setLeaveEarlyDetails(leaveEarlyDetails);
		}

		//定位异常
		List<UserSignDetail> locateAbnormalCount = details.stream().filter(o -> Convert.toInt(o.getSignType(), -1) == 2 || Convert.toInt(o.getSignOutType(), -1) == 2).collect(Collectors.toList());
		List<UserSignDetail> locateAbnormalCount1 = details.stream().filter(o -> Convert.toInt(o.getSignType(), -1) == 2).collect(Collectors.toList());
		List<UserSignDetail> locateAbnormalCount2 = details.stream().filter(o -> Convert.toInt(o.getSignOutType(), -1) == 2).collect(Collectors.toList());
		userSignDetailVo.setLocateAbnormalCount(locateAbnormalCount1.size() + locateAbnormalCount2.size());
		List<UserSignAbnormalVo> locateAbnormalDetails = new ArrayList<>(15);
		for (UserSignDetail userSignDetail : locateAbnormalCount) {
			UserSignAbnormalVo userSignAbnormalVo = new UserSignAbnormalVo();
			final Date date = userSignDetail.getBeSignDate();

			userSignAbnormalVo.setDate(DateUtil.format(date, "yyyy/MM/dd"));
			if (Convert.toInt(userSignDetail.getSignType(), -1) == 2 && Convert.toInt(userSignDetail.getSignOutType(), -1) == 2) {
				userSignAbnormalVo.setMsg("签到定位异常;签退定位异常");
			} else if (Convert.toInt(userSignDetail.getSignType(), -1) == 2) {
				userSignAbnormalVo.setMsg("签到定位异常");
			} else if (Convert.toInt(userSignDetail.getSignOutType(), -1) == 2) {
				userSignAbnormalVo.setMsg("签退定位异常");
			}
			locateAbnormalDetails.add(userSignAbnormalVo);
		}
		if (locateAbnormalDetails.size() > 0) {
			userSignDetailVo.setLocateAbnormalDetails(locateAbnormalDetails);
		}

		//补卡
		List<UserSignDetail> newSignCounts = details.stream().filter(o -> o.getNewSignTime() != null || o.getNewSignOutTime() != null).collect(Collectors.toList());
		List<UserSignDetail> newSignCounts1 = details.stream().filter(o -> o.getNewSignTime() != null).collect(Collectors.toList());
		List<UserSignDetail> newSignCounts2 = details.stream().filter(o -> o.getNewSignOutTime() != null).collect(Collectors.toList());
		userSignDetailVo.setNewSignCounts(newSignCounts1.size() + newSignCounts2.size());
		List<UserSignAbnormalVo> newSignDetails = new ArrayList<>(16);
		for (UserSignDetail userSignDetail : newSignCounts) {
			UserSignAbnormalVo userSignAbnormalVo = new UserSignAbnormalVo();
			final Date date = userSignDetail.getBeSignDate();
			if (userSignDetail.getNewSignTime() == null) {
				userSignAbnormalVo.setMsg("签退补卡");
			} else {
				userSignAbnormalVo.setMsg("签到补卡");
			}
			if (userSignDetail.getNewSignTime() != null && userSignDetail.getNewSignOutTime() != null) {
				userSignAbnormalVo.setMsg("签到补卡;签退补卡");
			}
			userSignAbnormalVo.setDate(DateUtil.format(date, "yyyy/MM/dd"));
			newSignDetails.add(userSignAbnormalVo);
		}
		if (newSignDetails.size() > 0) {
			userSignDetailVo.setNewSignDetails(newSignDetails);
		}

		//缺卡
		final Long yyyyMMdd = Convert.toLong(DateUtil.format(new Date(), "yyyyMMdd"));
		List<UserSignDetail> noSignCounts = details.stream().filter(o -> o.getHoliday() == 0 && !o.getSignDate().equals(yyyyMMdd) && (o.getSignTime() == null || o.getSignOutTime() == null)).collect(Collectors.toList());
		List<UserSignDetail> noSignCounts1 = details.stream().filter(o -> o.getHoliday() == 0 && !o.getSignDate().equals(yyyyMMdd) && o.getSignTime() == null).collect(Collectors.toList());
		List<UserSignDetail> noSignCounts2 = details.stream().filter(o -> o.getHoliday() == 0 && !o.getSignDate().equals(yyyyMMdd) && o.getSignOutTime() == null).collect(Collectors.toList());
		userSignDetailVo.setNoSignCounts(noSignCounts1.size() + noSignCounts2.size());
		List<UserSignAbnormalVo> noSignDetails = new ArrayList<>();
		for (UserSignDetail userSignDetail : noSignCounts) {
			UserSignAbnormalVo userSignAbnormalVo = new UserSignAbnormalVo();
			final Long signTime = userSignDetail.getSignTime();
			if (signTime == null) {
				userSignAbnormalVo.setMsg("签到缺卡");
			} else {
				userSignAbnormalVo.setMsg("签退缺卡");
			}
			if (userSignDetail.getSignTime() == null && userSignDetail.getSignOutTime() == null) {
				userSignAbnormalVo.setMsg("签到缺卡;签退缺卡");
			}
			final String format = DateUtil.format(userSignDetail.getBeSignDate(), "yyyy/MM/dd");
			userSignAbnormalVo.setDate(format);
			if (!format.equals(DateUtil.format(new Date(), "yyyy/MM/dd"))) {
				noSignDetails.add(userSignAbnormalVo);
			}
		}
		if (noSignDetails.size() > 0) {
			userSignDetailVo.setNoSignDetails(noSignDetails);
		}


		//加班
		List<UserSignDetail> workOverCounts = details.stream().filter(o -> o.getHoliday() == 1 && o.getSignTime() != null & o.getSignOutTime() != null).collect(Collectors.toList());
		userSignDetailVo.setWorkOverCounts(workOverCounts.size());
		List<UserSignAbnormalVo> workOverDetails = new ArrayList<>(20);
		Integer workOverHours = userSignDetailVo.getWorkOverHours();

		for (UserSignDetail userSignDetail : workOverCounts) {
			UserSignAbnormalVo userSignAbnormalVo = new UserSignAbnormalVo();
			userSignAbnormalVo.setDate(DateUtil.format(userSignDetail.getBeSignDate(), "yyyy/MM/dd"));
			final long between = DateUtil.between(new Date(userSignDetail.getSignTime()), new Date(userSignDetail.getSignOutTime()), DateUnit.MINUTE);
			if (Convert.toInt(between) >= DateUtils.HOURS_MINUTE) {
				userSignAbnormalVo.setMsg("加班" + DateUtils.minuteToHours(Convert.toInt(between)));
			} else {
				userSignAbnormalVo.setMsg("加班" + between + "分钟");
			}

			workOverDetails.add(userSignAbnormalVo);
			workOverHours = workOverHours + Convert.toInt(between);
		}
		if (workOverDetails.size() > 0) {
			userSignDetailVo.setWorkOverDetails(workOverDetails);
		}
		userSignDetailVo.setWorkOverHours(workOverHours);


		//实际出勤
		List<UserSignDetail> workDays1 = details.stream().filter(o -> o.getHoliday() == 0 && o.getSignTime() != null && o.getSignOutTime() != null).collect(Collectors.toList());
		List<UserSignDetail> workDays2 = details.stream().filter(o -> o.getHoliday() == 0 && o.getSignTime() == null && o.getSignOutTime() == null && o.getNewSignTime() != null & o.getNewSignOutTime() != null).collect(Collectors.toList());
		userSignDetailVo.setWorkDays(workDays1.size() + workDays2.size());


		//休息天数
		List<UserSignDetail> noWorkDays = details.stream().filter(o -> o.getHoliday() == 1).collect(Collectors.toList());
		userSignDetailVo.setNoWorkDays(noWorkDays.size());
		return userSignDetailVo;
	}

	@Override
	public RestUserSignDetailVo getRestUserSignDetail(SignDetailSearchDTO signDetailSearchDTO) {
		signDetailSearchDTO.setEndDate(null);
		signDetailSearchDTO.setBeginDate(null);
		//考勤魔法值不再定义，具体参考数据库字段意思和model对象说明
		RestUserSignDetailVo restUserSignDetailVo = new RestUserSignDetailVo();
		List<UserSignDetail> detailList = baseMapper.getRestUserSignDetail(signDetailSearchDTO);
		final List<DeptVO> signDeptTree = deptService.getSignDeptTree(AuthUtil.getTenantId(), signDetailSearchDTO.getParentId());
		detailList = deptConvert(detailList, signDeptTree);

		final Map<Long, List<UserSignDetail>> map = detailList.stream().filter(o -> o.getUserId() != null).collect(Collectors.groupingBy(UserSignDetail::getUserId));

		final List<UserSignDetail> details = detailList.stream().filter(o -> o.getUserId() != null && o.getSignTime() != null && o.getSignOutTime() != null).collect(Collectors.toList());
		final List<Long> userIds = details.stream().map(UserSignDetail::getUserId).distinct().collect(Collectors.toList());
		restUserSignDetailVo.setCounts(userIds.size());

		List<UserSignCommonVo> userSignList = new ArrayList<>(16);
		for (Long userId : userIds) {
			UserSignDetail userSignDetail = map.get(userId).get(0);
			UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
			userSignCommonVo.setUserName(userSignDetail.getRealName());
			userSignCommonVo.setUserId(userSignDetail.getUserId());
			userSignCommonVo.setIsNode(false);
			userSignCommonVo.setFloor(2);
			final long between2 = DateUtil.between(new Date(userSignDetail.getSignTime()), new Date(userSignDetail.getSignOutTime()), DateUnit.MINUTE);
			userSignCommonVo.setUserCoutns(Convert.toInt(between2));
			if (between2 >= DateUtils.HOURS_MINUTE) {
				userSignCommonVo.setMsg("加班" + DateUtils.minuteToHours(Convert.toInt(between2)));
			} else {
				userSignCommonVo.setMsg("加班" + between2 + "分钟");
			}
			userSignList.add(userSignCommonVo);
		}
		UserSignCommonVo userSign = new UserSignCommonVo();
		userSign.setSignTypeName("加班");
		if (userSignList.size() > 0) {
			userSign.setMsg("加班" + userSignList.size() + "人");
			userSign.setUserCoutns(userSignList.size());
			userSign.setFloor(1);
			Collections.sort(userSignList);
			userSign.setList(userSignList);
		}
		restUserSignDetailVo.setUserSign(userSign);

		final Map<String, List<UserSignDetail>> collect = detailList.stream().filter(o -> o.getUserId() != null && o.getSignTime() != null && o.getSignOutTime() != null && o.getDeptName() != null).collect(Collectors.groupingBy(UserSignDetail::getDeptName));
		final List<String> deptNames = detailList.stream().filter(o -> o.getUserId() != null && o.getSignTime() != null && o.getSignOutTime() != null && o.getDeptName() != null).map(UserSignDetail::getDeptName).distinct().collect(Collectors.toList());
		List<UserSignCommonVo> groupSignList = new ArrayList<>(16);
		//按组处理
		for (String deptName : deptNames) {
			UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
			userSignCommonVo.setDeptName(deptName);
			userSignCommonVo.setFloor(2);
			List<UserSignDetail> userSignDetails = collect.get(deptName);
			List<UserSignDetail> details1 = userSignDetails.stream().collect(
				Collectors.collectingAndThen(
					Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getUserId()))), ArrayList::new)
			);
			userSignDetails = details1;
			userSignCommonVo.setMsg(userSignDetails.size() + "人");
			userSignCommonVo.setUserCoutns(userSignDetails.size());
			List<UserSignCommonVo> list = new ArrayList<>(16);
			for (UserSignDetail userSignDetail : userSignDetails) {
				if (userSignDetail.getSignOutTime() != null && userSignDetail.getSignTime() != null) {
					UserSignCommonVo userSignCommonVo2 = new UserSignCommonVo();
					userSignCommonVo2.setUserName(userSignDetail.getRealName());
					userSignCommonVo2.setIsNode(false);
					userSignCommonVo2.setFloor(3);
					int between = Convert.toInt(DateUtil.between(new Date(userSignDetail.getSignTime()), new Date(userSignDetail.getSignOutTime()), DateUnit.MINUTE));
					userSignCommonVo2.setUserCoutns(Convert.toInt(between));
					if (between >= DateUtils.HOURS_MINUTE) {
						userSignCommonVo2.setMsg("加班" + DateUtils.minuteToHours(between));
					} else {
						userSignCommonVo2.setMsg("加班" + between + "分钟");
					}
					list.add(userSignCommonVo2);
				}
			}
			if (list.size() > 0) {
				Collections.sort(list);
				userSignCommonVo.setList(list);
			}
			groupSignList.add(userSignCommonVo);
		}
		UserSignCommonVo groupSign = new UserSignCommonVo();
		groupSign.setSignTypeName("加班");
		if (groupSignList.size() > 0) {
			groupSign.setMsg("加班" + userSignList.size() + "人");
			groupSign.setUserCoutns(userSignList.size());
			groupSign.setFloor(1);
			Collections.sort(groupSignList);
			groupSign.setList(groupSignList);
		}
		restUserSignDetailVo.setGroupSign(groupSign);
		return restUserSignDetailVo;
	}

	@Override
	public WorkUserSignDetailVo getWorkUserSignDetail(SignDetailSearchDTO signDetailSearchDTO) {
		signDetailSearchDTO.setEndDate(null);
		signDetailSearchDTO.setBeginDate(null);
		//考勤魔法值不再定义，具体参考数据库字段意思和model对象说明
		final List<MaintainSignSeting> list = maintainSignSetingService.list();
		final Map<Long, List<MaintainSignSeting>> map = list.stream().collect(Collectors.groupingBy(MaintainSignSeting::getId));

		WorkUserSignDetailVo workUserSignDetailVo = new WorkUserSignDetailVo();
		List<UserSignDetail> detailList = baseMapper.getRestUserSignDetail(signDetailSearchDTO);
		final List<DeptVO> signDeptTree = deptService.getSignDeptTree(AuthUtil.getTenantId(), signDetailSearchDTO.getParentId());
		detailList = deptConvert(detailList, signDeptTree);


		//计划出勤人员
		final int planUserCount = detailList.stream().map(UserSignDetail::getUserId).distinct().collect(Collectors.toList()).size();
		final List<String> planUserNames = detailList.stream().map(UserSignDetail::getRealName).distinct().collect(Collectors.toList());
		workUserSignDetailVo.setPlanUserCount(planUserCount);

		//实际出勤人员
		final List<Long> workUsers = detailList.stream().filter(o -> o.getHoliday() == 0 && o.getSignTime() != null).map(UserSignDetail::getUserId).distinct().collect(Collectors.toList());
		final List<String> workUserNames = detailList.stream().filter(o -> o.getHoliday() == 0 && o.getSignTime() != null).map(UserSignDetail::getRealName).distinct().collect(Collectors.toList());
		workUserSignDetailVo.setWorkUserCount(workUsers.size());
		workUserSignDetailVo.setWorkUserNames(workUserNames);
		planUserNames.removeAll(workUserNames);
		workUserSignDetailVo.setPlanUserNames(planUserNames);

		//迟到人员
		final int beLateCount = detailList.stream().filter(o -> Convert.toInt(o.getSignBeLate(), -1) == 0).map(UserSignDetail::getUserId).distinct().collect(Collectors.toList()).size();
		workUserSignDetailVo.setBeLateCount(beLateCount);

		//早退
		final int leaveEarlyCount = detailList.stream().filter(o -> Convert.toInt(o.getSignOutLeaveEarly(), -1) == 0).map(UserSignDetail::getUserId).distinct().collect(Collectors.toList()).size();
		workUserSignDetailVo.setLeaveEarlyCount(leaveEarlyCount);

		//定位异常
		final int locateAbnormalCount = detailList.stream().filter(o -> Convert.toInt(o.getSignType(), -1) == 2 || Convert.toInt(o.getSignOutType(), -1) == 2).map(UserSignDetail::getUserId).distinct().collect(Collectors.toList()).size();
		workUserSignDetailVo.setLocateAbnormalCount(locateAbnormalCount);

		final int newSignCounts = detailList.stream().filter(o -> o.getNewSignTime() != null || o.getNewSignOutTime() != null).map(UserSignDetail::getUserId).distinct().collect(Collectors.toList()).size();
		workUserSignDetailVo.setNewSignCounts(newSignCounts);

		final List<Long> collect = detailList.stream().filter(o -> o.getSignTime() == null).map(UserSignDetail::getUserId).distinct().collect(Collectors.toList());
		final List<Long> collect1 = detailList.stream().filter(o -> o.getSignOutTime() == null).map(UserSignDetail::getUserId).distinct().collect(Collectors.toList());
		collect.addAll(collect1);
		final List<Long> userIds = collect.stream().distinct().collect(Collectors.toList());
		final int noSignCounts = userIds.size();
		workUserSignDetailVo.setNoSignCounts(noSignCounts);

		List<UserSignCommonVo> userSignList = new ArrayList<>(16);
		for (UserSignDetail userSignDetail : detailList) {
			//迟到
			final Integer signBeLate = Convert.toInt(userSignDetail.getSignBeLate(), -1);
			if (signBeLate == 0) {
				UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
				final Integer minute = getSignBeLateMinute(map, userSignDetail);
				if (minute >= DateUtils.HOURS_MINUTE) {
					userSignCommonVo.setMsg("迟到" + DateUtils.minuteToHours(minute));
				} else {
					userSignCommonVo.setMsg("迟到" + minute + "分钟");
				}

				userSignCommonVo.setUserName(userSignDetail.getRealName());
				userSignCommonVo.setSignTypeName(SignTypeEnum.SIGN_BELATE.getName());
				userSignCommonVo.setDeptName(userSignDetail.getDeptName());
				userSignCommonVo.setDeptId(userSignDetail.getDeptId());
				userSignCommonVo.setUserId(userSignDetail.getUserId());

				//时间设置到人排序里面共用即可
				userSignCommonVo.setUserCoutns(minute);
				userSignList.add(userSignCommonVo);
			}

			//早退
			final Integer signOutLeaveEarly = Convert.toInt(userSignDetail.getSignOutLeaveEarly(), -1);
			if (signOutLeaveEarly == 0) {
				final Integer minute = getSignOutLeaveEarlyMinute(map, userSignDetail);
				UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
				if (minute >= DateUtils.HOURS_MINUTE) {
					userSignCommonVo.setMsg("早退" + DateUtils.minuteToHours(minute));
				} else {
					userSignCommonVo.setMsg("早退" + minute + "分钟");
				}
				userSignCommonVo.setUserName(userSignDetail.getRealName());
				userSignCommonVo.setSignTypeName(SignTypeEnum.SIGN_LEAVEEARLY.getName());
				userSignCommonVo.setDeptName(userSignDetail.getDeptName());
				userSignCommonVo.setDeptId(userSignDetail.getDeptId());
				userSignCommonVo.setUserId(userSignDetail.getUserId());
				userSignCommonVo.setUserCoutns(minute);
				userSignList.add(userSignCommonVo);
			}

			//定位异常
			if (Convert.toInt(userSignDetail.getSignType(), -1) == 2 || Convert.toInt(userSignDetail.getSignOutType(), -1) == 2) {
				UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
				if (Convert.toInt(userSignDetail.getSignType(), -1) == 2 && Convert.toInt(userSignDetail.getSignOutType(), -1) == 2) {
					userSignCommonVo.setMsg("签到异常,签退异常");
				} else {
					if (Convert.toInt(userSignDetail.getSignType(), -1) == 2) {
						userSignCommonVo.setMsg("签到异常");
					}
					if (Convert.toInt(userSignDetail.getSignOutType(), -1) == 2) {
						userSignCommonVo.setMsg("签退异常");
					}
				}
				userSignCommonVo.setUserName(userSignDetail.getRealName());
				userSignCommonVo.setSignTypeName(SignTypeEnum.SIGN_LOCATEABNORMAL.getName());
				userSignCommonVo.setDeptName(userSignDetail.getDeptName());
				userSignCommonVo.setDeptId(userSignDetail.getDeptId());
				userSignCommonVo.setUserId(userSignDetail.getUserId());
				userSignList.add(userSignCommonVo);
			}

			//补卡
			if (userSignDetail.getNewSignTime() != null || userSignDetail.getNewSignOutTime() != null) {
				UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
				if (userSignDetail.getNewSignTime() != null && userSignDetail.getNewSignOutTime() != null) {
					userSignCommonVo.setMsg("签到补卡,签退补卡");
				} else {
					if (userSignDetail.getNewSignTime() != null) {
						userSignCommonVo.setMsg("签到补卡");
					}
					if (userSignDetail.getNewSignOutTime() != null) {
						userSignCommonVo.setMsg("签退补卡");
					}
				}
				userSignCommonVo.setUserName(userSignDetail.getRealName());
				userSignCommonVo.setSignTypeName(SignTypeEnum.SIGN_NEWSIGN.getName());
				userSignCommonVo.setDeptName(userSignDetail.getDeptName());
				userSignCommonVo.setDeptId(userSignDetail.getDeptId());
				userSignCommonVo.setUserId(userSignDetail.getUserId());
				userSignList.add(userSignCommonVo);
			}

			//缺卡
			final Long signDate = userSignDetail.getSignDate();
			final Long today = Convert.toLong(DateUtil.format(new Date(), "yyyyMMdd"));
			if (userSignDetail.getHoliday() == 0 && (userSignDetail.getSignTime() == null || userSignDetail.getSignOutTime() == null) && !signDate.equals(today)) {
				UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
				if (userSignDetail.getSignTime() == null && userSignDetail.getSignOutTime() == null) {
					userSignCommonVo.setMsg("签到缺卡,签退缺卡");
				} else {
					if (userSignDetail.getSignTime() == null) {
						userSignCommonVo.setMsg("签到缺卡");
					}
					if (userSignDetail.getSignOutTime() == null) {
						userSignCommonVo.setMsg("签退缺卡");
					}
				}
				userSignCommonVo.setUserName(userSignDetail.getRealName());
				userSignCommonVo.setSignTypeName(SignTypeEnum.SIGN_NOSIGN.getName());
				userSignCommonVo.setDeptName(userSignDetail.getDeptName());
				userSignCommonVo.setDeptId(userSignDetail.getDeptId());
				userSignCommonVo.setUserId(userSignDetail.getUserId());
				userSignList.add(userSignCommonVo);
			}
		}

		//处理分组
		Map<String, List<UserSignCommonVo>> listMap = userSignList.stream().collect(Collectors.groupingBy(UserSignCommonVo::getSignTypeName));
		final List<String> signTypeNames = SignTypeEnum.dateUserSignTypeList();
		//按人处理
		List<UserSignCommonVo> userMap = new ArrayList<>(5);
		for (String signTypeName : signTypeNames) {
			UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
			userSignCommonVo.setSignTypeName(signTypeName);
			userSignCommonVo.setFloor(1);
			final List<UserSignCommonVo> userSignCommonVos = listMap.get(signTypeName);
			if (userSignCommonVos != null) {
				final Integer userSize = Convert.toInt(userSignCommonVos.stream().map(UserSignCommonVo::getUserName).distinct().collect(Collectors.toList()).size(), 0);
				userSignCommonVo.setMsg(userSize + "人");
				userSignCommonVo.setUserCoutns(userSize);
				userSignCommonVos.forEach(o -> {
					o.setIsNode(false);
					o.setFloor(2);
				});
				List<UserSignCommonVo> uniqueByNameAndSex = userSignCommonVos.stream().collect(
					Collectors.collectingAndThen(
						Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getUserId()))), ArrayList::new)
				);
				Collections.sort(uniqueByNameAndSex);
				userSignCommonVo.setList(uniqueByNameAndSex);
			}
			userMap.add(userSignCommonVo);
		}
		Collections.sort(userMap);
		workUserSignDetailVo.setUserMap(userMap);

		//按组处理
		List<UserSignCommonVo> groupMap2 = new ArrayList<>(5);
		for (String signTypeName : signTypeNames) {
			UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
			userSignCommonVo.setSignTypeName(signTypeName);
			userSignCommonVo.setFloor(1);
			List<UserSignCommonVo> groupMap3 = new ArrayList<>(5);

			final List<UserSignCommonVo> userSignCommonVos = listMap.get(signTypeName);
			if (userSignCommonVos != null && userSignCommonVos.size() > 0) {
				final Integer userSize = Convert.toInt(userSignCommonVos.stream().map(UserSignCommonVo::getUserName).distinct().collect(Collectors.toList()).size(), 0);
				userSignCommonVo.setMsg(userSize + "人");
				userSignCommonVo.setUserCoutns(userSize);
				final Map<Long, List<UserSignCommonVo>> map1 = userSignCommonVos.stream().collect(Collectors.groupingBy(UserSignCommonVo::getDeptId));
				final List<Long> deptIds = userSignCommonVos.stream().map(UserSignCommonVo::getDeptId).distinct().collect(Collectors.toList());

				for (Long deptId : deptIds) {
					UserSignCommonVo userSignCommonVo1 = new UserSignCommonVo();
					final List<UserSignCommonVo> userSignCommonVos1 = map1.get(deptId);
					if (userSignCommonVos1 != null) {
						userSignCommonVo1.setFloor(2);
						userSignCommonVo1.setDeptName(userSignCommonVos1.get(0).getDeptName());
						final Integer userSize2 = Convert.toInt(userSignCommonVos1.stream().map(UserSignCommonVo::getUserName).distinct().collect(Collectors.toList()).size(), 0);
						userSignCommonVo1.setMsg(userSize2 + "人");
						userSignCommonVo1.setUserCoutns(userSize2);
						userSignCommonVos1.forEach(o -> {
							o.setIsNode(false);
							o.setFloor(3);
						});

						List<UserSignCommonVo> uniqueByNameAndSex = userSignCommonVos1.stream().collect(
							Collectors.collectingAndThen(
								Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getUserId()))), ArrayList::new)
						);
						Collections.sort(uniqueByNameAndSex);
						userSignCommonVo1.setList(uniqueByNameAndSex);
					}
					groupMap3.add(userSignCommonVo1);
				}
				Collections.sort(groupMap3);
				userSignCommonVo.setList(groupMap3);

			}
			groupMap2.add(userSignCommonVo);
		}
		Collections.sort(groupMap2);
		workUserSignDetailVo.setGroupMap(groupMap2);

		final List<UserSignCommonVo> workRate = getWorkRate(workUsers, signDeptTree, workUserNames);
		workUserSignDetailVo.setWorkRateLists(workRate);
		return workUserSignDetailVo;
	}

	@Override
	public DateUserSignDetailVo getDateUserSignDetail(SignDetailSearchDTO signDetailSearchDTO) {
		signDetailSearchDTO.setSearchDate(null);
		if (signDetailSearchDTO.getEndDate().getTime() > new Date().getTime()) {
			signDetailSearchDTO.setEndDate(new Date());
		}

		//考勤魔法值不再定义，具体参考数据库字段意思和model对象说明
		final List<MaintainSignSeting> list = maintainSignSetingService.list();
		final Map<Long, List<MaintainSignSeting>> map = list.stream().collect(Collectors.groupingBy(MaintainSignSeting::getId));

		DateUserSignDetailVo dateUserSignDetailVo = new DateUserSignDetailVo();
		List<UserSignDetail> detailList = baseMapper.getRestUserSignDetail(signDetailSearchDTO);
		final List<DeptVO> signDeptTree = deptService.getSignDeptTree(AuthUtil.getTenantId(), signDetailSearchDTO.getParentId());
		detailList = deptConvert(detailList, signDeptTree);

		final List<UserSignDetail> userSignDetails = signTypeDetail(detailList);
		//迟到
		final int beLateCount = userSignDetails.stream().filter(o -> o.getHoliday() == 0 && Convert.toInt(o.getSignBeLate(), -1) == 0).collect(Collectors.toList()).size();
		dateUserSignDetailVo.setBeLateCount(beLateCount);

		//早退
		final int leaveEarlyCount = userSignDetails.stream().filter(o -> o.getHoliday() == 0 && Convert.toInt(o.getSignOutLeaveEarly(), -1) == 0).collect(Collectors.toList()).size();
		dateUserSignDetailVo.setLeaveEarlyCount(leaveEarlyCount);

		//定位异常放在按人分组时获取
		//final int locateAbnormalCount = userSignDetails.stream().filter(o -> Convert.toInt(o.getSignType(), -1) == 2 || Convert.toInt(o.getSignOutType(), -1) == 2).collect(Collectors.toList()).size();
		//dateUserSignDetailVo.setLocateAbnormalCount(locateAbnormalCount);

		//补卡
		final int newSignCounts = userSignDetails.stream().filter(o -> o.getNewSignTime() != null || o.getNewSignOutTime() != null).collect(Collectors.toList()).size();
		dateUserSignDetailVo.setNewSignCounts(newSignCounts);

		//缺卡放在按人分组时获取
		//final int noSignCounts = userSignDetails.stream().filter(o -> o.getHoliday() == 0 && o.getSignTime() == null).collect(Collectors.toList()).size();
		//final int noSignCounts2 = userSignDetails.stream().filter(o -> o.getHoliday() == 0 && o.getSignOutTime() == null).collect(Collectors.toList()).size();
		//dateUserSignDetailVo.setNoSignCounts(noSignCounts + noSignCounts2);

		//加班次数
		final int workOverCounts = userSignDetails.stream().filter(o -> o.getHoliday() == 1 && o.getSignTime() != null && o.getSignOutTime() != null).collect(Collectors.toList()).size();
		dateUserSignDetailVo.setWorkOverCounts(workOverCounts);

		List<UserSignCommonVo> userSignList = new ArrayList<>(16);
		for (UserSignDetail userSignDetail : detailList) {
			//迟到
			final Integer signBeLate = Convert.toInt(userSignDetail.getSignBeLate(), -1);
			if (signBeLate == 0 && userSignDetail.getHoliday() == 0) {
				UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
				final Integer minute = getSignBeLateMinute(map, userSignDetail);
				if (minute >= DateUtils.HOURS_MINUTE) {
					userSignCommonVo.setMsg("迟到" + DateUtils.minuteToHours(minute));
				} else {
					userSignCommonVo.setMsg("迟到" + minute + "分钟");
				}
				userSignCommonVo.setMinuteOrHours(minute);
				userSignCommonVo.setUserName(userSignDetail.getRealName());
				userSignCommonVo.setUserId(userSignDetail.getUserId());
				userSignCommonVo.setSignTypeName(SignTypeEnum.SIGN_BELATE.getName());
				userSignCommonVo.setDeptName(userSignDetail.getDeptName());
				userSignCommonVo.setDeptId(userSignDetail.getDeptId());
				userSignCommonVo.setDate(DateUtil.format(userSignDetail.getBeSignDate(), "yyyy/MM/dd"));
				userSignList.add(userSignCommonVo);
			}

			//早退
			final Integer signOutLeaveEarly = Convert.toInt(userSignDetail.getSignOutLeaveEarly(), -1);
			if (signOutLeaveEarly == 0 && userSignDetail.getHoliday() == 0) {
				final Integer minute = getSignOutLeaveEarlyMinute(map, userSignDetail);
				UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
				if (minute >= DateUtils.HOURS_MINUTE) {
					userSignCommonVo.setMsg("早退" + DateUtils.minuteToHours(minute));
				} else {
					userSignCommonVo.setMsg("早退" + minute + "分钟");
				}
				userSignCommonVo.setMinuteOrHours(minute);
				userSignCommonVo.setUserId(userSignDetail.getUserId());
				userSignCommonVo.setUserName(userSignDetail.getRealName());
				userSignCommonVo.setSignTypeName(SignTypeEnum.SIGN_LEAVEEARLY.getName());
				userSignCommonVo.setDeptName(userSignDetail.getDeptName());
				userSignCommonVo.setDeptId(userSignDetail.getDeptId());
				userSignCommonVo.setDate(DateUtil.format(userSignDetail.getBeSignDate(), "yyyy/MM/dd"));
				userSignList.add(userSignCommonVo);
			}

			//定位异常
			if (Convert.toInt(userSignDetail.getSignType(), -1) == 2 || Convert.toInt(userSignDetail.getSignOutType(), -1) == 2) {
				UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
				if (Convert.toInt(userSignDetail.getSignType(), -1) == 2 && Convert.toInt(userSignDetail.getSignOutType(), -1) == 2) {
					userSignCommonVo.setMsg("签到异常,签退异常");
				} else {
					if (Convert.toInt(userSignDetail.getSignType(), -1) == 2) {
						userSignCommonVo.setMsg("签到异常");
					}
					if (Convert.toInt(userSignDetail.getSignOutType(), -1) == 2) {
						userSignCommonVo.setMsg("签退异常");
					}
				}
				userSignCommonVo.setDate(DateUtil.format(userSignDetail.getBeSignDate(), "yyyy/MM/dd"));
				userSignCommonVo.setUserName(userSignDetail.getRealName());
				userSignCommonVo.setUserId(userSignDetail.getUserId());
				userSignCommonVo.setDeptId(userSignDetail.getDeptId());
				userSignCommonVo.setSignTypeName(SignTypeEnum.SIGN_LOCATEABNORMAL.getName());
				userSignCommonVo.setDeptName(userSignDetail.getDeptName());
				userSignList.add(userSignCommonVo);
			}

			//补卡
			if (userSignDetail.getNewSignTime() != null || userSignDetail.getNewSignOutTime() != null) {
				UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
				if (userSignDetail.getNewSignTime() != null && userSignDetail.getNewSignOutTime() != null) {
					userSignCommonVo.setMsg("签到补卡,签退补卡");
				} else {
					if (userSignDetail.getNewSignTime() != null) {
						userSignCommonVo.setMsg("签到补卡");
					}
					if (userSignDetail.getNewSignOutTime() != null) {
						userSignCommonVo.setMsg("签退补卡");
					}
				}
				userSignCommonVo.setUserName(userSignDetail.getRealName());
				userSignCommonVo.setSignTypeName(SignTypeEnum.SIGN_NEWSIGN.getName());
				userSignCommonVo.setDeptName(userSignDetail.getDeptName());
				userSignCommonVo.setUserId(userSignDetail.getUserId());
				userSignCommonVo.setDeptId(userSignDetail.getDeptId());
				userSignCommonVo.setDate(DateUtil.format(userSignDetail.getBeSignDate(), "yyyy/MM/dd"));
				userSignList.add(userSignCommonVo);
			}

			//加班

			if (userSignDetail.getHoliday() == 1 && userSignDetail.getSignTime() != null && userSignDetail.getSignOutTime() != null) {
				UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
				final Integer anInt = Convert.toInt(DateUtil.between(new Date(userSignDetail.getSignTime()), new Date(userSignDetail.getSignOutTime()), DateUnit.MINUTE));
				if (anInt >= DateUtils.HOURS_MINUTE) {
					userSignCommonVo.setMsg("加班" + DateUtils.minuteToHours(anInt));
				} else {
					userSignCommonVo.setMsg("加班" + anInt + "分钟");
				}
				userSignCommonVo.setMinuteOrHours(anInt);

				userSignCommonVo.setUserName(userSignDetail.getRealName());
				userSignCommonVo.setSignTypeName(SignTypeEnum.SIGN_OVERTIME.getName());
				userSignCommonVo.setUserId(userSignDetail.getUserId());
				userSignCommonVo.setDeptName(userSignDetail.getDeptName());
				userSignCommonVo.setDeptId(userSignDetail.getDeptId());
				userSignCommonVo.setDate(DateUtil.format(userSignDetail.getBeSignDate(), "yyyy/MM/dd"));
				userSignList.add(userSignCommonVo);
			}

			//缺卡
			final Long signDate = userSignDetail.getSignDate();
			final Long today = Convert.toLong(DateUtil.format(new Date(), "yyyyMMdd"));
			if (userSignDetail.getHoliday() == 0 && (userSignDetail.getSignTime() == null || userSignDetail.getSignOutTime() == null) && !signDate.equals(today)) {
				UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
				if (userSignDetail.getSignTime() == null && userSignDetail.getSignOutTime() == null) {
					userSignCommonVo.setMsg("签到缺卡,签退缺卡");
				} else {
					if (userSignDetail.getSignTime() == null) {
						userSignCommonVo.setMsg("签到缺卡");
					}
					if (userSignDetail.getSignOutTime() == null) {
						userSignCommonVo.setMsg("签退缺卡");
					}
				}
				userSignCommonVo.setUserName(userSignDetail.getRealName());
				userSignCommonVo.setSignTypeName(SignTypeEnum.SIGN_NOSIGN.getName());
				userSignCommonVo.setDeptName(userSignDetail.getDeptName());
				userSignCommonVo.setDeptId(userSignDetail.getDeptId());
				userSignCommonVo.setUserId(userSignDetail.getUserId());
				userSignCommonVo.setDate(DateUtil.format(userSignDetail.getBeSignDate(), "yyyy/MM/dd"));
				userSignList.add(userSignCommonVo);
			}
		}

		final List<String> signTypeList = SignTypeEnum.dateUserSignTypeList();
		final Map<String, List<UserSignCommonVo>> stringListMap = userSignList.stream().collect(Collectors.groupingBy(UserSignCommonVo::getSignTypeName));

		//按人统计
		List<UserGroupSignDetailVo> userGroup = new ArrayList<>(16);
		for (String signType : signTypeList) {
			//处理第一个层级 签到状态类型
			UserGroupSignDetailVo userGroupSignDetailVo = new UserGroupSignDetailVo();
			userGroupSignDetailVo.setSignTypeName(signType);
			userGroupSignDetailVo.setFloor(1);
			List<UserSignCommonVo> userSignCommonVos = stringListMap.get(signType);
			userSignCommonVos = userSignCommonDistinct(userSignCommonVos);
			if (userSignCommonVos != null && userSignCommonVos.size() > 0) {
				final Map<String, List<UserSignCommonVo>> userGroupDetailMap = userSignCommonVos.stream().collect(Collectors.groupingBy(UserSignCommonVo::getUserName));

				//过滤次数重复,因为一个人员在多个组
				final Map<String, Map<String, List<UserSignCommonVo>>> mapMap = userSignCommonVos.stream().filter(o -> o.getUserId() != null && o.getDate() != null).collect(Collectors.groupingBy(UserSignCommonVo::getUserName, Collectors.groupingBy(UserSignCommonVo::getDate)));
				final Collection<Map<String, List<UserSignCommonVo>>> values = mapMap.values();
				int signCoutns = 0;
				for (Map<String, List<UserSignCommonVo>> mapList : values) {
					signCoutns = signCoutns + mapList.size();
				}

				final List<String> users = userSignCommonVos.stream().map(UserSignCommonVo::getUserName).distinct().collect(Collectors.toList());
				if (signType.equals(SignTypeEnum.SIGN_NOSIGN.getName())) {
					final List<String> strings = userSignCommonVos.stream().filter(o -> o.getMsg().contains("缺卡")).map(UserSignCommonVo::getMsg).collect(Collectors.toList());
					int counts = 0;
					for (String str : strings) {
						counts = counts + str.split(",").length;
					}
					userGroupSignDetailVo.setMsg(users.size() + "人(共" + counts + "次)");
					userGroupSignDetailVo.setUserCoutns(users.size());
					dateUserSignDetailVo.setNoSignCounts(counts);
				} else if (signType.equals(SignTypeEnum.SIGN_LOCATEABNORMAL.getName())) {
					final List<String> strings = userSignCommonVos.stream().filter(o -> o.getMsg().contains("异常")).map(UserSignCommonVo::getMsg).collect(Collectors.toList());
					int counts = 0;
					for (String str : strings) {
						counts = counts + str.split(",").length;
					}
					userGroupSignDetailVo.setMsg(users.size() + "人(共" + counts + "次)");
					userGroupSignDetailVo.setUserCoutns(users.size());
					dateUserSignDetailVo.setLocateAbnormalCount(counts);
				} else if (signType.equals(SignTypeEnum.SIGN_NEWSIGN.getName())) {
					final List<String> strings = userSignCommonVos.stream().filter(o -> o.getMsg().contains("补卡")).map(UserSignCommonVo::getMsg).collect(Collectors.toList());
					int counts = 0;
					for (String str : strings) {
						counts = counts + str.split(",").length;
					}
					userGroupSignDetailVo.setMsg(users.size() + "人(共" + counts + "次)");
					userGroupSignDetailVo.setUserCoutns(users.size());
					dateUserSignDetailVo.setNewSignCounts(counts);
				} else {
					userGroupSignDetailVo.setMsg(mapMap.size() + "人(共" + signCoutns + "次)");
					userGroupSignDetailVo.setUserCoutns(mapMap.size());
				}
				List<UserSignCommonVo> userSignDetailList = new ArrayList<>();

				//处理第二个层级 按照姓名
				for (String userName : users) {
					UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
					userSignCommonVo.setUserName(userName);
					userSignCommonVo.setFloor(2);
					final List<UserSignCommonVo> userSignCommonVos1 = userSignCommonDistinct(userGroupDetailMap.get(userName).stream().distinct().collect(Collectors.toList()));
					//分钟数
					Integer minute = 0;
					//次数
					Integer signTypeCounts = 0;

					List<UserSignAbnormalVo> userSignAbnormalVos = new ArrayList<>(16);

					//处理第三个层级 按照日期
					for (UserSignCommonVo userSignCommonvo : userSignCommonVos1) {
						UserSignAbnormalVo userSignAbnormalVo = new UserSignAbnormalVo();
						userSignAbnormalVo.setDate(userSignCommonvo.getDate());
						userSignAbnormalVo.setMsg(userSignCommonvo.getMsg());
						userSignAbnormalVo.setFloor(3);
						minute = minute + Convert.toInt(userSignCommonvo.getMinuteOrHours(), 0);
						signTypeCounts = signTypeCounts + userSignCommonvo.getMsg().split(",").length;
						userSignAbnormalVos.add(userSignAbnormalVo);
					}
					if (signType.equals(SignTypeEnum.SIGN_BELATE.getName()) || signType.equals(SignTypeEnum.SIGN_LEAVEEARLY.getName())) {

						if (minute >= DateUtils.HOURS_MINUTE) {
							userSignCommonVo.setMsg(userSignCommonVos1.size() + "次(共" + DateUtils.minuteToHours(minute) + ")");
						} else {
							userSignCommonVo.setMsg(userSignCommonVos1.size() + "次(共" + minute + "分钟)");
						}

						userSignCommonVo.setUserCoutns(userSignCommonVos1.size());
					}
					if (signType.equals(SignTypeEnum.SIGN_LOCATEABNORMAL.getName()) || signType.equals(SignTypeEnum.SIGN_NEWSIGN.getName()) || signType.equals(SignTypeEnum.SIGN_NOSIGN.getName())) {
						userSignCommonVo.setMsg(signTypeCounts + "次");
						userSignCommonVo.setUserCoutns(signTypeCounts);
					}
					if (signType.equals(SignTypeEnum.SIGN_OVERTIME.getName())) {
						if (minute >= DateUtils.HOURS_MINUTE) {
							userSignCommonVo.setMsg(userSignCommonVos1.size() + "次(共" + DateUtils.minuteToHours(minute) + ")");
						} else {
							userSignCommonVo.setMsg(userSignCommonVos1.size() + "次(共" + minute + "分钟)");
						}

						userSignCommonVo.setUserCoutns(userSignCommonVos1.size());
					}

					userSignCommonVo.setList(userSignAbnormalVos);
					userSignDetailList.add(userSignCommonVo);
				}


				if (userSignDetailList.size() > 0) {
					List<UserSignCommonVo> uniqueByNameAndSex = userSignDetailList.stream().collect(
						Collectors.collectingAndThen(
							Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getUserName()))), ArrayList::new)
					);
					Collections.sort(uniqueByNameAndSex);
					userGroupSignDetailVo.setList(uniqueByNameAndSex);
				}
			} else {
				userGroupSignDetailVo.setMsg("0人(共0次)");
			}

			userGroup.add(userGroupSignDetailVo);
		}
		Collections.sort(userGroup);
		dateUserSignDetailVo.setUserList(userGroup);

		//按组统计
		List<UserGroupSignDetailVo> groupDetailList = new ArrayList<>(16);
		for (String signType : signTypeList) {
			//第一级签到状态处理
			UserGroupSignDetailVo userGroupSignDetailVo = new UserGroupSignDetailVo();
			userGroupSignDetailVo.setSignTypeName(signType);
			userGroupSignDetailVo.setFloor(1);
			List<UserSignCommonVo> userSignCommonVos = stringListMap.get(signType);
			if (userSignCommonVos != null && userSignCommonVos.size() > 0) {
				//第二级处理 按照部门分组

				//单独处理缺卡逻辑
				final List<String> oneUsers = userSignCommonVos.stream().map(UserSignCommonVo::getUserName).distinct().collect(Collectors.toList());

				//处理多组人员的逻辑
				final Map<String, Map<String, List<UserSignCommonVo>>> mapMap = userSignCommonVos.stream().filter(o -> o.getUserName() != null && o.getDate() != null).collect(Collectors.groupingBy(UserSignCommonVo::getUserName, Collectors.groupingBy(UserSignCommonVo::getDate)));
				final Collection<Map<String, List<UserSignCommonVo>>> values = mapMap.values();
				int signCoutns = 0;
				for (Map<String, List<UserSignCommonVo>> mapList : values) {
					signCoutns = signCoutns + mapList.size();
				}

				if (signType.equals(SignTypeEnum.SIGN_NOSIGN.getName()) || signType.equals(SignTypeEnum.SIGN_LOCATEABNORMAL.getName()) || signType.equals(SignTypeEnum.SIGN_NEWSIGN.getName())) {
					int counts = 0;
					for (UserSignCommonVo userSignCommonVo : userSignCommonDistinct(userSignCommonVos)) {
						final int length = userSignCommonVo.getMsg().split(",").length;
						counts = counts + length;
					}
					userGroupSignDetailVo.setMsg(oneUsers.size() + "人(共" + counts + "次)");
					userGroupSignDetailVo.setUserCoutns(oneUsers.size());
				} else {
					userGroupSignDetailVo.setMsg(mapMap.size() + "人(共" + signCoutns + "次)");
					userGroupSignDetailVo.setUserCoutns(mapMap.size());
				}

				final Map<Long, List<UserSignCommonVo>> listMap = userSignCommonVos.stream().collect(Collectors.groupingBy(UserSignCommonVo::getDeptId));
				final List<Long> deptIds = userSignCommonVos.stream().map(UserSignCommonVo::getDeptId).distinct().collect(Collectors.toList());
				List<UserSignCommonVo> groupList = new ArrayList<>(16);
				for (Long deptId : deptIds) {
					List<UserSignCommonVo> userSignCommonVos1 = listMap.get(deptId);
					//按照组分完以后过滤不同组的重复数据
					userSignCommonVos1 = userSignCommonDistinct(userSignCommonVos1);
					final String deptName = userSignCommonVos1.get(0).getDeptName();
					final List<String> users = userSignCommonVos1.stream().map(UserSignCommonVo::getUserName).distinct().collect(Collectors.toList());
					UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
					userSignCommonVo.setDeptName(deptName);
					userSignCommonVo.setFloor(2);
					//处理第二级的缺卡信息
					if (signType.equals(SignTypeEnum.SIGN_NOSIGN.getName()) || signType.equals(SignTypeEnum.SIGN_NEWSIGN.getName()) || signType.equals(SignTypeEnum.SIGN_LOCATEABNORMAL.getName())) {
						int counts = 0;
						for (UserSignCommonVo userSignCommon : userSignCommonVos1) {
							final int length = userSignCommon.getMsg().split(",").length;
							counts = counts + length;
						}
						userSignCommonVo.setMsg(users.size() + "人(共" + counts + "次)");
						userSignCommonVo.setUserCoutns(users.size());
					} else {
						userSignCommonVo.setMsg(users.size() + "人(共" + userSignCommonVos1.size() + "次)");
						userSignCommonVo.setUserCoutns(users.size());
					}


					//处理第三级 按照姓名分组
					final Map<String, List<UserSignCommonVo>> listMap1 = userSignCommonVos1.stream().collect(Collectors.groupingBy(UserSignCommonVo::getUserName));
					final List<String> userNames = userSignCommonVos1.stream().map(UserSignCommonVo::getUserName).distinct().collect(Collectors.toList());
					List<UserSignCommonVo> userNameList = new ArrayList<>(16);
					for (String userName : userNames) {
						final List<UserSignCommonVo> userSignCommonVos2 = listMap1.get(userName);
						UserSignCommonVo userSignCommonVo1 = new UserSignCommonVo();
						userSignCommonVo1.setUserName(userName);
						userSignCommonVo1.setDeptName(deptName);
						userSignCommonVo1.setFloor(3);
						//分钟数
						Integer minute = 0;
						//次数
						Integer signTypeCounts = 0;
						//处理第四级
						List<UserSignAbnormalVo> userSignAbnormalVos = new ArrayList<>(16);
						for (UserSignCommonVo userSignCommonvo : userSignCommonVos2) {
							UserSignAbnormalVo userSignAbnormalVo = new UserSignAbnormalVo();
							userSignAbnormalVo.setDate(userSignCommonvo.getDate());
							userSignAbnormalVo.setMsg(userSignCommonvo.getMsg());
							userSignAbnormalVo.setFloor(4);
							minute = minute + Convert.toInt(userSignCommonvo.getMinuteOrHours(), 0);
							signTypeCounts = signTypeCounts + userSignCommonvo.getMsg().split(",").length;
							userSignAbnormalVos.add(userSignAbnormalVo);
						}
						if (signType.equals(SignTypeEnum.SIGN_BELATE.getName()) || signType.equals(SignTypeEnum.SIGN_LEAVEEARLY.getName())) {
							if (minute >= DateUtils.HOURS_MINUTE) {
								userSignCommonVo1.setMsg(userSignCommonVos2.size() + "次(共" + DateUtils.minuteToHours(minute) + ")");
							} else {
								userSignCommonVo1.setMsg(userSignCommonVos2.size() + "次(共" + minute + "分钟)");
							}
							userSignCommonVo1.setUserCoutns(userSignCommonVos2.size());
						}
						if (signType.equals(SignTypeEnum.SIGN_LOCATEABNORMAL.getName()) || signType.equals(SignTypeEnum.SIGN_NEWSIGN.getName()) || signType.equals(SignTypeEnum.SIGN_NOSIGN.getName())) {
							userSignCommonVo1.setMsg(signTypeCounts + "次");
							userSignCommonVo1.setUserCoutns(signTypeCounts);
						}
						if (signType.equals(SignTypeEnum.SIGN_OVERTIME.getName())) {
							if (minute >= DateUtils.HOURS_MINUTE) {
								userSignCommonVo1.setMsg(userSignCommonVos2.size() + "次(共" + DateUtils.minuteToHours(minute) + ")");
							} else {
								userSignCommonVo1.setMsg(userSignCommonVos2.size() + "次(共" + minute + "分钟)");
							}
							userSignCommonVo1.setUserCoutns(userSignCommonVos2.size());
						}
						userSignCommonVo1.setList(userSignAbnormalVos);
						userNameList.add(userSignCommonVo1);
					}

					if (userNameList.size() > 0) {
						List<UserSignCommonVo> uniqueByNameAndSex = userNameList.stream().collect(
							Collectors.collectingAndThen(
								Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getUserName()))), ArrayList::new)
						);
						Collections.sort(uniqueByNameAndSex);
						userSignCommonVo.setList(uniqueByNameAndSex);
					}

					groupList.add(userSignCommonVo);
				}
				Collections.sort(groupList);
				userGroupSignDetailVo.setList(groupList);
			} else {
				userGroupSignDetailVo.setMsg("0人(共0次)");
			}

			groupDetailList.add(userGroupSignDetailVo);
		}
		Collections.sort(groupDetailList);
		dateUserSignDetailVo.setGroupList(groupDetailList);
		return dateUserSignDetailVo;
	}

	@Override
	public List<SignWorkUserVo> getWorkUserList(List<Long> userIds) {


		return baseMapper.getWorkUserList(userIds);
	}

	@Override
	public HomeUserSignCountVO selectUserSign(Long userId) {

		LocalDate now = LocalDate.now();
		String monthFirstDay = LocalDate.of(now.getYear(), now.getMonth(), 1).toString();
		String yesterday = DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd");
		HomeUserSignCountVO result = baseMapper.selectUserSignMonthCount(userId, monthFirstDay, yesterday);
		UserSignDetail today = super.getOne(Wrappers.<UserSignDetail>lambdaQuery().eq(UserSignDetail::getUserId, userId).eq(UserSignDetail::getSignDate, DateUtil.format(DateUtil.date(), "yyyyMMdd")));
		result.setSignStatus(0);
		result.setSignOutStatus(0);
		if (ObjectUtil.isNotEmpty(today)) {
			if (ObjectUtil.isNotEmpty(today.getSignTime())) {
				result.setSignStatus(1);
			}
			if (ObjectUtil.isNotEmpty(today.getSignOutTime())) {
				result.setSignOutStatus(1);
			}
		}
		return result;
	}

	/**
	 * 免费节假日API
	 * 参考：https://timor.tech/api/holiday
	 * 失败尝试重调3次
	 *
	 * @param year 年份
	 */
	@Override
	public JSONObject getHolidays(Integer year) {
		if (Func.isEmpty(year)) {
			year = DateUtil.year(DateUtil.date());
		}

		// redis获取
		String holidayJson = bladeRedis.get(CacheNames.HOLIDAY_KEY + year);
		if (Func.isNotEmpty(holidayJson)) {
			return holidaysTo2024(holidayJson, year);
		} else {
			int count = 0;
			JSONObject jsonObject = null;
			String url = String.format("http://timor.tech/api/holiday/year/%s?week=N", year);
			do {
				String result = HttpRequest.get(url).execute().body();
				jsonObject = JSONUtil.parseObj(result, false, true);
			} while (Integer.valueOf(jsonObject.get("code").toString()) != 0 && ++count < 3);

			// 若调用成功
			if (Func.isNotEmpty(jsonObject) && Integer.valueOf(jsonObject.get("code").toString()) == 0) {
				bladeRedis.set(CacheNames.HOLIDAY_KEY + year, jsonObject.get("holiday").toString());
				return holidaysTo2024(jsonObject.get("holiday").toString(), year);
			}

			return null;
		}
	}

	/**
	 * 获取迟到的分钟数
	 *
	 * @param map
	 * @param userSignDetail
	 * @return
	 */
	private Integer getSignBeLateMinute(Map<Long, List<MaintainSignSeting>> map, UserSignDetail userSignDetail) {
		final Date date = userSignDetail.getBeSignDate();
		final MaintainSignSeting maintainSignSeting = map.get(userSignDetail.getSignSettingId()).get(0);
		String signDate1 = maintainSignSeting.getSignDate();
		signDate1 = signDate1.split(":").length == 2 ? signDate1 + ":00" : signDate1;
		final String signDate = DateUtil.format(date, "yyyy-MM-dd") + " " + signDate1;
		final DateTime dateTime = DateUtil.parse(signDate, "yyyy-MM-dd HH:mm:ss");
		final Integer minute = Convert.toInt(DateUtil.between(dateTime, new Date(userSignDetail.getSignTime()), DateUnit.MINUTE));
		return minute;
	}


	/**
	 * 获取早退的分钟数
	 *
	 * @param map
	 * @param userSignDetail
	 * @return
	 */
	private Integer getSignOutLeaveEarlyMinute(Map<Long, List<MaintainSignSeting>> map, UserSignDetail userSignDetail) {
		final Date date = userSignDetail.getBeSignDate();
		final MaintainSignSeting maintainSignSeting = map.get(userSignDetail.getSignSettingId()).get(0);
		String signDate1 = maintainSignSeting.getSignOutDate();
		signDate1 = signDate1.split(":").length == 2 ? signDate1 + ":00" : signDate1;
		final String signDate = DateUtil.format(date, "yyyy-MM-dd") + " " + signDate1;
		final DateTime dateTime = DateUtil.parse(signDate, "yyyy-MM-dd HH:mm:ss");
		final Integer minute = Convert.toInt(DateUtil.between(dateTime, new Date(userSignDetail.getSignOutTime()), DateUnit.MINUTE));
		return minute;
	}


	private List<UserSignDetail> deptConvert(List<UserSignDetail> list, List signDeptTree) {

		//表示部门
		int typeDept = 2;
		DeptTreeNode deptTreeNode = (DeptTreeNode) signDeptTree.get(0);
		final List children = deptTreeNode.getChildren();

		//剔除未在组织架构下的用户部门
		List<UserSignDetail> resultList = new ArrayList<>(16);
		for (UserSignDetail userSignDetail : list) {
			if (JSON.toJSONString(children).contains(userSignDetail.getDeptId().toString())) {
				resultList.add(userSignDetail);
			}
		}
		list = resultList;


		List<DeptTreeNode> otherDept = new ArrayList<>(16);
		for (Object treeNode : children) {
			DeptTreeNode deptTreeNode1 = (DeptTreeNode) treeNode;
			if (deptTreeNode1.getType() == typeDept) {
				otherDept.add(deptTreeNode1);
			}
		}
		//查找上级组
		for (Object treeNode : children) {
			final String string = JSON.toJSONString(treeNode);
			DeptTreeNode deptTreeNode1 = (DeptTreeNode) treeNode;
			for (UserSignDetail userSignDetail : list) {
				if (string.contains(userSignDetail.getDeptId().toString())) {
					userSignDetail.setDeptId(deptTreeNode1.getId());
					userSignDetail.setDeptName(deptTreeNode1.getTitle());
				}
			}
		}


		Long deptId = System.currentTimeMillis();
		if (otherDept.size() > 0) {
			final String string = JSON.toJSONString(otherDept);
			for (UserSignDetail userSignDetail : list) {
				if (string.contains(userSignDetail.getUserId().toString())) {
					userSignDetail.setDeptName("未分组");
					userSignDetail.setDeptId(deptId);
				}
			}
		}

		return list;
	}


	/**
	 * 获取出勤排行榜数据
	 *
	 * @param userIds      出勤人员ids
	 * @param signDeptTree 部门上级id
	 */
	private List<UserSignCommonVo> getWorkRate(List<Long> userIds, List signDeptTree, List<String> workUserNames) {
		//表示部门
		int typeDept = 1;
		DeptTreeNode deptTreeNode = (DeptTreeNode) signDeptTree.get(0);
		final List children = deptTreeNode.getChildren();
		List<DeptTreeNode> otherDept = new ArrayList<>(16);
		List<UserSignCommonVo> resultList = new ArrayList<>(16);
		for (Object treeNode : children) {
			DeptTreeNode deptTreeNode1 = (DeptTreeNode) treeNode;
			UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
			if (deptTreeNode1.getType() == typeDept) {
				userSignCommonVo.setDeptName(deptTreeNode1.getTitle());
				final Integer userCounts = getUserCounts(userIds, deptTreeNode1);
				userSignCommonVo.setMsg(userCounts + "/" + deptTreeNode1.getTotal());
				userSignCommonVo.setWorkUserNames(getUserNames(workUserNames, deptTreeNode1));
				final List<String> deptUserNames = getDeptUserNames(deptTreeNode1, new ArrayList<>());
				deptUserNames.removeAll(userSignCommonVo.getWorkUserNames());
				userSignCommonVo.setPlanUserNames(deptUserNames);
				userSignCommonVo.setWorkRate(Convert.toBigDecimal(userCounts).divide(Convert.toBigDecimal(deptTreeNode1.getTotal()), 3, BigDecimal.ROUND_UP));
				resultList.add(userSignCommonVo);
			} else {
				otherDept.add(deptTreeNode1);
			}
		}

		if (otherDept.size() > 0) {
			UserSignCommonVo userSignCommonVo = new UserSignCommonVo();
			userSignCommonVo.setDeptName("未分组");
			Integer counts = 0;
			for (Long userId : userIds) {
				final String userIdStr = userId.toString();
				final String jsonString = JSON.toJSONString(otherDept);
				if (jsonString.contains(userIdStr)) {
					counts = counts + 1;
				}
			}
			List<String> workUserList = new ArrayList<>(16);
			for (String workUserName : workUserNames) {
				final String jsonString = JSON.toJSONString(otherDept);
				if (jsonString.contains(workUserName)) {
					workUserList.add(workUserName);
				}
			}

			List<String> planUserList = new ArrayList<>(16);
			for (DeptTreeNode deptTreeNode1 : otherDept) {
				final List<String> deptUserNames = getDeptUserNames(deptTreeNode1, new ArrayList<>());
				planUserList.addAll(deptUserNames);
			}
			userSignCommonVo.setWorkUserNames(workUserList);
			planUserList.removeAll(workUserList);
			userSignCommonVo.setPlanUserNames(planUserList);
			userSignCommonVo.setMsg(counts + "/" + otherDept.size());
			userSignCommonVo.setWorkRate(Convert.toBigDecimal(counts).divide(Convert.toBigDecimal(otherDept.size()), 3, BigDecimal.ROUND_UP));

			resultList.add(userSignCommonVo);
		}
		Collections.sort(resultList);
		return resultList;
	}

	/**
	 * 获取这个组包含了哪些考勤人员
	 * 只获取用户ids
	 *
	 * @param userIds
	 * @param deptStatisticalVO
	 * @return
	 */
	private Integer getUserCounts(List<Long> userIds, DeptTreeNode deptStatisticalVO) {
		Integer counts = 0;
		for (Long userId : userIds) {
			final String userIdStr = userId.toString();
			final String jsonString = JSON.toJSONString(deptStatisticalVO);
			if (jsonString.contains(userIdStr)) {
				counts = counts + 1;
			}
		}
		return counts;
	}


	/**
	 * 获取这个组包含了哪些考勤人员
	 * 只获取名称
	 *
	 * @param userNames         用户名称
	 * @param deptStatisticalVO
	 * @return
	 */
	private List<String> getUserNames(List<String> userNames, DeptTreeNode deptStatisticalVO) {
		List<String> resultList = new ArrayList<>(16);
		for (String userName : userNames) {
			final String jsonString = JSON.toJSONString(deptStatisticalVO);
			if (jsonString.contains(userName)) {
				resultList.add(userName);
			}
		}
		return resultList;
	}

	/**
	 * 获取这个组包含了哪些考勤人员
	 * 只获取名称
	 *
	 * @param deptStatisticalVO
	 * @return
	 */
	private List<String> getDeptUserNames(DeptTreeNode deptStatisticalVO, List<String> list) {
		if (deptStatisticalVO.getType() == 2) {
			list.add(deptStatisticalVO.getTitle());
		} else if (deptStatisticalVO.getHasChildren() == true) {
			final List children = deptStatisticalVO.getChildren();
			for (Object treeNode : children) {
				DeptTreeNode deptTreeNode1 = (DeptTreeNode) treeNode;
				getDeptUserNames(deptTreeNode1, list);
			}
		}
		return list;
	}


	/**
	 * UserSignCommonVo 去重
	 *
	 * @param list
	 * @return
	 */
	private List<UserSignCommonVo> userSignCommonDistinct(List<UserSignCommonVo> list) {
		if (list == null || list.size() == 0) {
			return new ArrayList<UserSignCommonVo>();
		}
		List<UserSignCommonVo> uniqueByNameAndSex = list.stream().collect(
			Collectors.collectingAndThen(
				Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getUserId() + ";" + o.getDate()))), ArrayList::new)
		);

		return uniqueByNameAndSex;
	}

	/**
	 * 过滤每个人要的重复 信息
	 *
	 * @param detailList 考勤明细
	 * @return 数据集
	 */
	private List<UserSignDetail> signTypeDetail(List<UserSignDetail> detailList) {
		return detailList.stream().collect(
			Collectors.collectingAndThen(
				Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getUserId() + ";" + o.getSignDate()))), ArrayList::new)
		);

	}


	/**
	 * 2024年格式转换
	 *
	 * @param holidayJson
	 * @param year
	 * @return 数据集
	 */
	private JSONObject holidaysTo2024(String holidayJson, Integer year) {
		JSONObject dataList = JSONUtil.parseObj(holidayJson);
		JSONObject jsonObject2024 = new JSONObject();
		jsonObject2024.putOpt("Year", year);
		jsonObject2024.putOpt("isReCreate", true);
		List<HolidayVo> list = new ArrayList<>();
		for (String key : dataList.keySet()) {
			HolidayVo holidayVo = new HolidayVo();
			JSONObject jsonObject = JSONUtil.parseObj(dataList.get(key).toString());
			JSONObject jsonObjectDay = new JSONObject();
			String monthDay = DateUtil.format(DateUtil.parse(jsonObject.get("date").toString(), "yyyy-MM-dd"), "MMdd");
			holidayVo.setMonthDay(monthDay);
			Integer wage = Convert.toInt(jsonObject.get("wage"));
			String name = Convert.toStr(jsonObject.get("name"));
			holidayVo.setRemark(name);
			if (wage == 3 || wage == 2) {
				//等于3表示节假日转换成2023年的格式type=1
				holidayVo.setType("1");
				list.add(holidayVo);
			} else if (wage == 1) {
				//等于1表示节假日补办
				holidayVo.setType("2");
				list.add(holidayVo);
			}
		}
		List<HolidayVo> collect = list.stream().sorted(Comparator.comparing(HolidayVo::getMonthDay)).collect(Collectors.toList());
		jsonObject2024.putOpt("JsonStr", collect);
		return jsonObject2024;
	}
}
